Skip to content

Conversation

c-miles
Copy link

@c-miles c-miles commented Oct 11, 2025

Fixes a memory leak in AnimatedProps that causes unbounded accumulation of child nodes in applications with frequent re-renders.

Fixes #2756. Builds on recent improvements in this area like #2800.

Background

During investigation of facebook/react-native#49217, I discovered this issue is specific to react-native-web. This area of the vendored Animated implementation has diverged from React Native core, where the AnimatedProps constructor does not call __attach().

Root Cause

The AnimatedProps constructor calls this.__attach() (line 35), then useAnimatedPropsLifecycle calls node.__attach() again (line 110 in useAnimatedProps.js). This causes the same AnimatedProps instance to add itself as a child to parent nodes twice.

Each re-render creates a new AnimatedProps with this double-attachment, but cleanup only removes one reference. The result is unbounded accumulation of duplicate children. In a stress test with 500 animated components re-rendering every 50ms, this produced 359,382 duplicate __addChild calls.

Live demo of the issue (note: Android/iOs works fine, but web version exhibits the leak)

Approach

This PR removes the constructor __attach() call entirely.

Why this is safe:

  • useLayoutEffect in useAnimatedProps (line 110) synchronously calls node.__attach() before browser paint
  • No code path requires immediate attachment during construction
  • React Native core's implementation proves this pattern works correctly

Initially considered adding a defensive check in __addChild() to prevent duplicates:

if (this._children.includes(child)) return

While this prevented the leak, it masked the underlying issue rather than addressing the root cause.

Impact

  • Breaking changes: None
  • Performance: Eliminates memory leak in animated applications
  • Compatibility: Aligns behavior with React Native core implementation

Removes __attach() call from AnimatedProps constructor that caused
duplicate child additions when combined with lifecycle hook.

The constructor was calling __attach(), then useLayoutEffect in
useAnimatedProps called it again on the same instance, causing each
AnimatedProps to be added as a child twice to its parent nodes.
This led to unbounded memory growth in applications with frequent
re-renders.

This change aligns with React Native core implementation, which does
not call __attach() in the AnimatedProps constructor
Copy link

This pull request is automatically built and testable in CodeSandbox.

To see build info of the built libraries, click here or the icon next to each commit SHA.

Latest deployment of this branch, based on commit e534ed9:

Sandbox Source
react-native-web-examples Configuration

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Memory Leak in Animated API with AnimatedWithChildren

1 participant